https://www.memotech.franken.de/FileFormats/Garmin_MPS_GDB_and_GFI_Format.pdf
*/
-#include <cmath> // for fabs
-#include <cstdio> // for printf, snprintf, sscanf, SEEK_SET, NULL
-#include <cstdlib> // for atoi, strtol, NULL
-#include <cstring> // for memset, strcmp, strstr, strchr, strlen, strncpy
-#include <ctime> // for strftime
-#include <iterator> // for next
+#include "gdb.h"
-#include <QByteArray> // for QByteArray
-#include <QList> // for QList
+#include <QByteArray> // for QByteArray, operator==
+#include <QList> // for QList<>::const_iterator, QList
#include <QString> // for QString, operator!=, operator==
-#include <QVector> // for QVector
#include <Qt> // for CaseInsensitive
-#include <QtGlobal> // for qPrintable, Q_UNUSED, foreach
+#include <QtGlobal> // for Q_UNUSED, qPrintable, foreach
-#include "defs.h"
+#include <cmath> // for fabs
+#include <cstdio> // for printf, snprintf, sscanf, SEEK_SET
+#include <cstdlib> // for atoi, strtol
+#include <cstring> // for memset, strstr, strchr, strcmp, strlen, strncpy
+#include <ctime> // for strftime, tm
+#include <iterator> // for next
+#include "defs.h" // for Waypoint, warning, fatal, route_head, UrlLink, bounds, mkshort, UrlList, unknown_alt, wp_flags, xfree, waypt_add_to_bounds, waypt_init_bounds, mkshort_del_handle, route_add_wpt, route_disp_all, waypt_bounds_valid, xmalloc, WAYPT_GET, WAYPT_SET, gb_color
#include "cet_util.h" // for cet_convert_init
-#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_flags_t, garmin_ilink_t, GMSD_GET, GMSD_SETSTR, GMSD_SET, garmin_fs_alloc, GMSD_FIND, GMSD_HAS
-#include "garmin_tables.h" // for gt_get_icao_country, gt_waypt_class_map_point, gt_color_index_by_rgb, gt_color_value, gt_waypt_classes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_gdb_display_mode_symbol, gt_waypt_class_user_waypoint, GDB, gt_display_mode_symbol
-#include "gbfile.h" // for gbfputint32, gbfgetint32, gbfread, gbfwrite, gbfgetc, gbfputc, gbfgetdbl, gbfgetcstr, gbfile, gbfclose, gbfputcstr, gbfcopyfrom, gbfrewind, gbfseek, gbftell, gbfopen_le, gbfgetcstr_old, gbfgetint16, gbfputdbl, gbfputint16
+#include "formspec.h" // for FormatSpecificDataList
+#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc
+#include "garmin_tables.h" // for gt_waypt_class_map_point, gt_color_index_by_rgb, gt_color_value, gt_waypt_classes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_gdb_display_mode_symbol, gt_get_icao_country, gt_waypt_class_user_waypoint, GDB, gt_display_mode_symbol
+#include "gbfile.h" // for gbfgetint32, gbfputint32, gbfgetc, gbfread, gbfwrite, gbfgetdbl, gbfputc, gbfgetcstr, gbfclose, gbfgetnativecstr, gbfopen_le, gbfile, gbfputcstr, gbfcopyfrom, gbfrewind, gbfseek, gbftell, gbfgetcstr_old, gbfgetint16, gbfgetuint32, gbfputdbl, gbfputint16
#include "grtcirc.h" // for RAD, gcdist, radtometers
#include "jeeps/gpsmath.h" // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg
#include "src/core/datetime.h" // for DateTime
#define DBG(a,b) if ((GDB_DEBUG & (a)) && (b))
-/*******************************************************************************/
-
-/* static char gdb_release[] = "$Revision: 1.74 $"; */
-static char gdb_release_date[] = "$Date: 2011-04-14 01:30:01 $";
-
-static gbfile* fin, *fout, *ftmp;
-static int gdb_ver, gdb_category;
-static bool gdb_roadbook;
-static bool gdb_hide_wpt;
-static bool gdb_hide_rpt;
-
-static QList<Waypoint*> wayptq_in, wayptq_out, wayptq_in_hidden;
-static short_handle short_h;
-
-static char* gdb_opt_category;
-static char* gdb_opt_ver;
-static char* gdb_opt_via;
-static char* gdb_opt_roadbook;
-static char* gdb_opt_bitcategory;
-static char* gdb_opt_drop_hidden_wpt;
-
-static int waypt_flag;
-static int route_flag;
-
-static int waypt_ct; /* informational: total number of waypoints in/out */
-static int waypth_ct; /* informational: total number of hidden waypoints in/out */
-static int rtept_ct; /* informational: total number of route points in/out */
-static int trkpt_ct; /* informational: total number of track points in/out */
-static int rte_ct; /* informational: total number of routes in/out */
-static int trk_ct; /* informational: total number of tracks in/out */
-
-/*******************************************************************************/
-
#define ELEMENTS(a) a->rte_waypt_ct()
#define NOT_EMPTY(a) (a && *a)
-static void
-gdb_flush_waypt_queue(QList<Waypoint*>* Q)
+void
+GdbFormat::gdb_flush_waypt_queue(QList<Waypoint*>* Q)
{
while (!Q->isEmpty()) {
}
#if GDB_DEBUG
-static void
-disp_summary(const gbfile* f)
+void
+GdbFormat::disp_summary(const gbfile* f) const
{
int i, len;
warning("\n");
}
#else
-#define disp_summary(a)
+void
+GdbFormat::disp_summary(const gbfile* /* f */) const
+{
+}
#endif
/*******************************************************************************/
#define FREAD_CSTR_AS_QSTR gbfgetcstr(fin)
-static char* gdb_fread_cstr(gbfile* fin);
-
-static QString fread_cstr()
+QString GdbFormat::fread_cstr() const
{
QString rv;
char* s = gdb_fread_cstr(fin);
return rv;
}
-static char*
-gdb_fread_cstr(gbfile* file_in)
+char*
+GdbFormat::gdb_fread_cstr(gbfile* file_in)
{
char* result = gbfgetcstr_old(file_in);
return result;
}
-static QString
-gdb_fread_strlist()
+QString
+GdbFormat::gdb_fread_strlist() const
{
QString res;
return qres;
}
-static Waypoint*
-gdb_find_wayptq(const QList<Waypoint*>* Q, const Waypoint* wpt, const char exact)
+Waypoint*
+GdbFormat::gdb_find_wayptq(const QList<Waypoint*>* Q, const Waypoint* wpt, const char exact)
{
QString name = wpt->shortname;
foreach (Waypoint* tmp, *Q) {
return nullptr;
}
-static Waypoint*
-gdb_reader_find_waypt(const Waypoint* wpt, const char exact)
+Waypoint*
+GdbFormat::gdb_reader_find_waypt(const Waypoint* wpt, const char exact) const
{
Waypoint* res = gdb_find_wayptq(&wayptq_in, wpt, exact);
if (res == nullptr) {
return res;
}
-static Waypoint*
-gdb_add_route_waypt(route_head* rte, Waypoint* ref, const int wpt_class)
+Waypoint*
+GdbFormat::gdb_add_route_waypt(route_head* rte, Waypoint* ref, const int wpt_class) const
{
Waypoint* tmp = gdb_reader_find_waypt(ref, 1);
if (tmp == nullptr) {
return res;
}
-static QString gdb_to_ISO8601_duration(unsigned int seconds)
+QString GdbFormat::gdb_to_ISO8601_duration(unsigned int seconds)
{
if (seconds == 0u) {
return QString("PT0S");
/*******************************************************************************/
/* TOOLS AND MACROS FOR THE WRITER */
/*-----------------------------------------------------------------------------*/
-static void FWRITE_CSTR(const QString& a)
+void GdbFormat::FWRITE_CSTR(const QString& a) const
{
if (a.isEmpty()) {
gbfputc(0, fout);
#define FWRITE_CSTR_LIST(a) gdb_write_cstr_list((a))
#define FWRITE_LATLON(a) gbfputint32(GPS_Math_Deg_To_Semi((a)),fout)
-static void
-gdb_write_cstr_list(const char* str)
+void
+GdbFormat::gdb_write_cstr_list(const char* str) const
{
if NOT_EMPTY(str) {
gbfputint32(1, fout);
}
}
-static void
-gdb_write_cstr_list(const QString& str)
+void
+GdbFormat::gdb_write_cstr_list(const QString& str) const
{
gdb_write_cstr_list(CSTRc(str));
}
-static void
-gdb_write_dbl(const double value, const double def)
+void
+GdbFormat::gdb_write_dbl(const double value, const double def) const
{
if (value == def) {
gbfputc(0, fout);
}
}
-static void
-gdb_write_time(const int time)
+void
+GdbFormat::gdb_write_time(const int time) const
{
if (time > 0) {
gbfputc(1, fout);
/* GDB "Garmin Database" READER CODE */
/*-----------------------------------------------------------------------------*/
-static void
-read_file_header()
+void
+GdbFormat::read_file_header()
{
char buf[128];
/*-----------------------------------------------------------------------------*/
-static Waypoint*
-read_waypoint(gt_waypt_classes_e* waypt_class_out)
+Waypoint*
+GdbFormat::read_waypoint(gt_waypt_classes_e* waypt_class_out)
{
char buf[128]; /* used for temporary stuff */
gt_waypt_classes_e wpt_class;
/*-----------------------------------------------------------------------------*/
-static route_head*
-read_route()
+route_head*
+GdbFormat::read_route()
{
rte_ct++;
int warnings = 0;
/*-----------------------------------------------------------------------------*/
-static route_head*
-read_track()
+route_head*
+GdbFormat::read_track()
{
char dummy;
/*******************************************************************************/
-static void
-gdb_rd_init(const QString& fname)
+void
+GdbFormat::rd_init(const QString& fname)
{
fin = gbfopen_le(fname, "rb", MYNAME);
ftmp = gbfopen_le(nullptr, "wb", MYNAME);
trk_ct = 0;
}
-static void
-gdb_rd_deinit()
+void
+GdbFormat::rd_deinit()
{
disp_summary(fin);
gdb_flush_waypt_queue(&wayptq_in);
gbfclose(fin);
}
-static void
-read_data()
+void
+GdbFormat::read()
{
int incomplete = 0; /* number of incomplete reads */
/*
* reset_short_handle: used for waypoint, route and track names
*/
-static void
-reset_short_handle(const char* defname)
+void
+GdbFormat::reset_short_handle(const char* defname)
{
if (short_h != nullptr) {
mkshort_del_handle(&short_h);
/* ----------------------------------------------------------------------------*/
-static void
-write_header()
+void
+GdbFormat::write_header() const
{
char buff[128], tbuff[32];
char* c;
* after each input module.
*/
-static void
-gdb_check_waypt(Waypoint* wpt)
+void
+GdbFormat::gdb_check_waypt(Waypoint* wpt)
{
double lat_orig = wpt->latitude;
double lon_orig = wpt->longitude;
/*-----------------------------------------------------------------------------*/
-static void
-write_waypoint(
+void
+GdbFormat::write_waypoint(
const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd,
const int icon, const int display)
{
}
}
-static void
-route_compute_bounds(const route_head* rte, bounds* bounds)
+void
+GdbFormat::route_compute_bounds(const route_head* rte, bounds* bounds)
{
waypt_init_bounds(bounds);
foreach (Waypoint* wpt, rte->waypoint_list) {
}
}
-static void
-route_write_bounds(bounds* bounds)
+void
+GdbFormat::route_write_bounds(bounds* bounds) const
{
if (waypt_bounds_valid(bounds)) {
FWRITE_C(0);
}
}
-static void
-write_route(const route_head* rte, const QString& rte_name)
+void
+GdbFormat::write_route(const route_head* rte, const QString& rte_name)
{
bounds bounds;
char zbuf[32], ffbuf[32];
}
}
-static void
-write_track(const route_head* trk, const QString& trk_name)
+void
+GdbFormat::write_track(const route_head* trk, const QString& trk_name)
{
int points = ELEMENTS(trk);
/*-----------------------------------------------------------------------------*/
-static void
-finalize_item(gbfile* origin, const char identifier)
+void
+GdbFormat::finalize_item(gbfile* origin, const char identifier)
{
int len = gbftell(fout);
/*-----------------------------------------------------------------------------*/
-static void
-write_waypoint_cb(const Waypoint* refpt)
+void
+GdbFormat::write_waypoint_cb(const Waypoint* refpt)
{
/* do this when backup always happens in main */
// but, but, casting away the const here is wrong...
}
}
-static void
-write_route_cb(const route_head* rte)
+void
+GdbFormat::write_route_cb(const route_head* rte)
{
if (ELEMENTS(rte) <= 0) {
return;
finalize_item(fsave, 'R');
}
-static void
-write_track_cb(const route_head* trk)
+void
+GdbFormat::write_track_cb(const route_head* trk)
{
if (ELEMENTS(trk) <= 0) {
return;
/*-----------------------------------------------------------------------------*/
-static void
-gdb_wr_init(const QString& fname)
+void
+GdbFormat::wr_init(const QString& fname)
{
fout = gbfopen_le(fname, "wb", MYNAME);
ftmp = gbfopen_le(nullptr, "wb", MYNAME);
trk_ct = 0;
}
-static void
-gdb_wr_deinit()
+void
+GdbFormat::wr_deinit()
{
disp_summary(fout);
gdb_flush_waypt_queue(&wayptq_out);
gbfclose(ftmp);
}
-static void
-write_data()
+void
+GdbFormat::write()
{
if (gdb_opt_ver) {
gdb_ver = atoi(gdb_opt_ver);
reset_short_handle("WPT");
route_flag = 0;
- waypt_disp_all(write_waypoint_cb);
+ auto write_waypoint_cb_lambda = [this](const Waypoint* waypointp)->void {
+ write_waypoint_cb(waypointp);
+ };
+ waypt_disp_all(write_waypoint_cb_lambda);
route_flag = 1;
- route_disp_all(nullptr, nullptr, write_waypoint_cb);
+ route_disp_all(nullptr, nullptr, write_waypoint_cb_lambda);
reset_short_handle("Route");
- route_disp_all(write_route_cb, nullptr, nullptr);
+ auto write_route_cb_lambda = [this](const route_head* rte)->void {
+ write_route_cb(rte);
+ };
+ route_disp_all(write_route_cb_lambda, nullptr, nullptr);
reset_short_handle("Track");
- track_disp_all(write_track_cb, nullptr, nullptr);
+ auto write_track_cb_lambda = [this](const route_head* rte)->void {
+ write_track_cb(rte);
+ };
+ track_disp_all(write_track_cb_lambda, nullptr, nullptr);
FWRITE_i32(2); /* finalize gdb with empty map segment */
FWRITE_CSTR("V");
FWRITE_C(1);
}
-
-/*******************************************************************************/
-
-static QVector<arglist_t> gdb_args = {
- {
- "cat", &gdb_opt_category,
- "Default category on output (1..16)",
- nullptr, ARGTYPE_INT, "1", "16", nullptr
- },
- {
- "bitscategory", &gdb_opt_bitcategory, "Bitmap of categories",
- nullptr, ARGTYPE_INT, "1", "65535", nullptr
- },
- {
- "ver", &gdb_opt_ver,
- "Version of gdb file to generate (1..3)",
- "2", ARGTYPE_INT, "1", "3", nullptr
- },
- {
- "via", &gdb_opt_via,
- "Drop route points that do not have an equivalent waypoint (hidden points)",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "dropwpt", &gdb_opt_drop_hidden_wpt,
- "Don't create waypoints for non-user points",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "roadbook", &gdb_opt_roadbook,
- "Include major turn points (with description) from calculated route",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
-
-};
-
-ff_vecs_t gdb_vecs = {
- ff_type_file,
- FF_CAP_RW_ALL,
- gdb_rd_init,
- gdb_wr_init,
- gdb_rd_deinit,
- gdb_wr_deinit,
- read_data,
- write_data,
- nullptr,
- &gdb_args,
- CET_CHARSET_MS_ANSI, 0 /* O.K.: changed to NON-FIXED */
- /* because of utf8 strings since GDB V3 */
- , NULL_POS_OPS
-};
-
-/*******************************************************************************/
--- /dev/null
+/*
+ Garmin GPS Database Reader/Writer
+
+ Copyright (C) 2005-2008 Olaf Klein, o.b.klein@gpsbabel.org
+ Mainly based on mapsource.c,
+ Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ A format description obtained from reverse-engineering is at
+ https://www.memotech.franken.de/FileFormats/Garmin_MPS_GDB_and_GFI_Format.pdf
+*/
+#ifndef GDB_H_INCLUDED_
+#define GDB_H_INCLUDED_
+
+#include <QList> // for QList
+#include <QString> // for QString
+#include <QVector> // for QVector
+
+#include "defs.h" // for arglist_t, Waypoint, route_head, ARGTYPE_BOOL, ARGTYPE_INT, ARG_NOMINMAX, bounds, CET_CHARSET_MS_ANSI, FF_CAP_RW_ALL, ff_cap, ff_type, ff_type_file, short_handle
+#include "format.h" // for Format
+#include "garmin_fs.h" // for garmin_fs_t
+#include "garmin_tables.h" // for gt_waypt_classes_e
+#include "gbfile.h" // for gbfile
+
+
+class GdbFormat : public Format
+{
+public:
+ QVector<arglist_t>* get_args() override
+ {
+ return &gdb_args;
+ }
+
+ ff_type get_type() const override
+ {
+ return ff_type_file;
+ }
+
+ QVector<ff_cap> get_cap() const override
+ {
+ return FF_CAP_RW_ALL;
+ }
+
+ QString get_encode() const override
+ {
+ return CET_CHARSET_MS_ANSI;
+ }
+
+ int get_fixed_encode() const override
+ {
+ /* O.K.: changed to NON-FIXED because of utf8 strings since GDB V3 */
+ return 0;
+ }
+
+ void rd_init(const QString& fname) override;
+ void read() override;
+ void rd_deinit() override;
+ void wr_init(const QString& fname) override;
+ void write() override;
+ void wr_deinit() override;
+
+private:
+ /* Constants */
+
+ /* static constexpr char gdb_release[] = "$Revision: 1.74 $"; */
+ static constexpr char gdb_release_date[] = "$Date: 2011-04-14 01:30:01 $";
+
+ /* Member Functions */
+
+ static void gdb_flush_waypt_queue(QList<Waypoint*>* Q);
+ void disp_summary(const gbfile* f) const;
+ QString fread_cstr() const;
+ static char* gdb_fread_cstr(gbfile* file_in);
+ QString gdb_fread_strlist() const;
+ static Waypoint* gdb_find_wayptq(const QList<Waypoint*>* Q, const Waypoint* wpt, char exact);
+ Waypoint* gdb_reader_find_waypt(const Waypoint* wpt, char exact) const;
+ Waypoint* gdb_add_route_waypt(route_head* rte, Waypoint* ref, int wpt_class) const;
+ static QString gdb_to_ISO8601_duration(unsigned int seconds);
+ void FWRITE_CSTR(const QString& a) const;
+ void gdb_write_cstr_list(const char* str) const;
+ void gdb_write_cstr_list(const QString& str) const;
+ void gdb_write_dbl(double value, double def) const;
+ void gdb_write_time(int time) const;
+ void read_file_header();
+ Waypoint* read_waypoint(gt_waypt_classes_e* waypt_class_out);
+ route_head* read_route();
+ route_head* read_track();
+ void reset_short_handle(const char* defname);
+ void write_header() const;
+ static void gdb_check_waypt(Waypoint* wpt);
+ void write_waypoint(const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd, int icon, int display);
+ static void route_compute_bounds(const route_head* rte, bounds* bounds);
+ void route_write_bounds(bounds* bounds) const;
+ void write_route(const route_head* rte, const QString& rte_name);
+ void write_track(const route_head* trk, const QString& trk_name);
+ void finalize_item(gbfile* origin, char identifier);
+ void write_waypoint_cb(const Waypoint* refpt);
+ void write_route_cb(const route_head* rte);
+ void write_track_cb(const route_head* trk);
+
+ /* Data Members */
+
+ gbfile* fin{}, *fout{}, *ftmp{};
+ int gdb_ver{}, gdb_category{};
+ bool gdb_roadbook{};
+ bool gdb_hide_wpt{};
+ bool gdb_hide_rpt{};
+
+ QList<Waypoint*> wayptq_in, wayptq_out, wayptq_in_hidden;
+ short_handle short_h{};
+
+ char* gdb_opt_category{};
+ char* gdb_opt_ver{};
+ char* gdb_opt_via{};
+ char* gdb_opt_roadbook{};
+ char* gdb_opt_bitcategory{};
+ char* gdb_opt_drop_hidden_wpt{};
+
+ int waypt_flag{};
+ int route_flag{};
+
+ int waypt_ct{}; /* informational: total number of waypoints in/out */
+ int waypth_ct{}; /* informational: total number of hidden waypoints in/out */
+ int rtept_ct{}; /* informational: total number of route points in/out */
+ int trkpt_ct{}; /* informational: total number of track points in/out */
+ int rte_ct{}; /* informational: total number of routes in/out */
+ int trk_ct{}; /* informational: total number of tracks in/out */
+
+ QVector<arglist_t> gdb_args = {
+ {
+ "cat", &gdb_opt_category,
+ "Default category on output (1..16)",
+ nullptr, ARGTYPE_INT, "1", "16", nullptr
+ },
+ {
+ "bitscategory", &gdb_opt_bitcategory, "Bitmap of categories",
+ nullptr, ARGTYPE_INT, "1", "65535", nullptr
+ },
+ {
+ "ver", &gdb_opt_ver,
+ "Version of gdb file to generate (1..3)",
+ "2", ARGTYPE_INT, "1", "3", nullptr
+ },
+ {
+ "via", &gdb_opt_via,
+ "Drop route points that do not have an equivalent waypoint (hidden points)",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "dropwpt", &gdb_opt_drop_hidden_wpt,
+ "Don't create waypoints for non-user points",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "roadbook", &gdb_opt_roadbook,
+ "Include major turn points (with description) from calculated route",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ }
+ };
+};
+#endif // GDB_H_INCLUDED_